﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Palluk.PassMaster.Passwords
{
    /// <summary>
    /// Represent a password object. Provide a password builder and related policy.
    /// </summary>
    public class PasswordBuilder
    {
        private static Random random = new Random();

        /// <summary>
        /// Provide to generate a new random password. 
        /// </summary>
        /// <param name="policy">The contract with password characteristics.</param>
        /// <returns>The new password</returns>
        public string Generate(Contract policy)
        {
            int lenght = policy.Min;
            if (policy.Min < policy.Max)
                lenght += random.Next(policy.Max - policy.Min);

            char[] newPassword = new char[lenght];
            for (int i = 0; i < newPassword.Count(); i++)
                newPassword[i] = RandomizeChar(Charset.GetLowers());

            if (policy.numerics > 0)
                for (int c = 0; c < policy.numerics; c++)
                    newPassword[RandomizeIndex(newPassword)] = RandomizeChar(Charset.GetNumbers());
            if (policy.upcases > 0)
                for (int c = 0; c < policy.upcases; c++)
                {
                    int index = RandomizeIndex(newPassword);
                    newPassword[index] = Char.ToUpper(newPassword[index]);
                }
            if (policy.symbols > 0)
                for (int c = 0; c < policy.symbols; c++)
                    newPassword[RandomizeIndex(newPassword)] = RandomizeChar(Charset.GetSymbols());

            return new string(newPassword);
        }

        public bool Validate()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Return a random char inner the array provided by parameter.
        /// </summary>
        /// <param name="ascii">An array of selectable chars.</param>
        /// <returns>The char choosed.</returns>
        private char RandomizeChar(char[] ascii)
        {
            return ascii[random.Next(0, ascii.Length)];
        }

        /// <summary>
        /// Chooses a random position into the array passed by parameter where the current value
        /// is a lower char.
        /// </summary>
        /// <param name="ascii">An array of selectable chars.</param>
        /// <returns>A random index.</returns>
        private int RandomizeIndex(char[] value)
        {
            List<int> avails = new List<int>();
            for (int c = 0; c < value.Length; c++)
                if (Char.IsLower(value[c]))
                    avails.Add(c);
            return avails[random.Next(avails.Count)];
        }
    }
}
